package cn.iocoder.yudao.module.wecom.service.chatgroup;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.wecom.dal.dataobject.apiconfig.WeComApiConfigDO;
import cn.iocoder.yudao.module.wecom.dal.dataobject.chatgroupmember.WeChatGroupMemberDO;
import cn.iocoder.yudao.module.wecom.dal.mysql.chatgroupmember.WeChatGroupMemberMapper;
import cn.iocoder.yudao.module.wecom.http.WeApi;
import cn.iocoder.yudao.module.wecom.mq.producer.SyncChatGroupProducer;
import cn.iocoder.yudao.module.wecom.mq.producer.SyncCustomerProducer;
import cn.iocoder.yudao.module.wecom.service.apiconfig.WeComApiConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import cn.iocoder.yudao.module.wecom.controller.admin.chatgroup.vo.*;
import cn.iocoder.yudao.module.wecom.dal.dataobject.chatgroup.WeChatGroupDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.wecom.dal.mysql.chatgroup.WeChatGroupMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.wecom.enums.ErrorCodeConstants.*;

/**
 * 客户群 Service 实现类
 *
 * @author 数创万维
 */
@Service
@Validated
@Slf4j
public class WeChatGroupServiceImpl implements WeChatGroupService {

    @Resource
    private WeChatGroupMapper weChatGroupMapper;

    @Resource
    private WeComApiConfigService weComApiConfigService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private SyncChatGroupProducer syncChatGroupProducer;

    @Resource
    private WeChatGroupMemberMapper weChatGroupMemberMapper;

    private final static String LOCK_KEY = "QW_CHAT_SYNC_LOCK:";

    @Override
    public List<WeChatGroupDO> getWeChatGroupList() {
        return weChatGroupMapper.selectList();
    }

    @Override
    public WeChatGroupDO getWeChatGroup(Long id) {
        return weChatGroupMapper.selectById(id);
    }

    @Override
    public WeChatGroupDO getWeChatGroupByChatId(String weChatId) {
        return weChatGroupMapper.selectOne(WeChatGroupDO::getChatId, weChatId);
    }

    @Override
    public List<WeChatGroupDO> getWeChatGroupListByChatIds(List<String> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return weChatGroupMapper.selectList(new LambdaQueryWrapperX<WeChatGroupDO>()
                .in(WeChatGroupDO::getChatId, ids)
        );
    }

    @Override
    public Map<String, WeChatGroupDO> getWeChatGroupMap(List<String> ids) {
        List<WeChatGroupDO> list = getWeChatGroupListByChatIds(ids);

        return CollectionUtils.convertMap(list, WeChatGroupDO::getChatId);
    }

    @Override
    public PageResult<WeChatGroupDO> getWeChatGroupPage(WeChatGroupPageReqVO pageReqVO) {
        return weChatGroupMapper.selectPage(pageReqVO);
    }


    @Override
    public List<String> getChatIdListByWeUserId(String weUserId) {
        if (StrUtil.isEmpty(weUserId)) {
            return Collections.emptyList();
        }
        List<WeChatGroupMemberDO> list = weChatGroupMemberMapper.selectList(
                new LambdaQueryWrapperX<WeChatGroupMemberDO>()
                        .eq(WeChatGroupMemberDO::getWeUserId, weUserId)
                        .eq(WeChatGroupMemberDO::getType, 1)
        );
        return list.stream().map(WeChatGroupMemberDO::getChatId).collect(Collectors.toList());
    }

    @Override
    public Long getChatGroupCountByWeUserId(String weUserId) {
        if (StrUtil.isEmpty(weUserId)) {
            return 0L;
        }
        return weChatGroupMemberMapper.selectCount(
                new LambdaQueryWrapperX<WeChatGroupMemberDO>()
                        .eq(WeChatGroupMemberDO::getWeUserId, weUserId)
//                        .eq(WeChatGroupMemberDO::getType, 1)
        );
    }

    @Override
    public List<String> getChatIdListByWeCustomerId(String weCustomerId) {
        if (StrUtil.isEmpty(weCustomerId)) {
            return Collections.emptyList();
        }
        List<WeChatGroupMemberDO> list = weChatGroupMemberMapper.selectList(
                new LambdaQueryWrapperX<WeChatGroupMemberDO>()
                        .eq(WeChatGroupMemberDO::getWeUserId, weCustomerId)
                        .eq(WeChatGroupMemberDO::getType, 2)
        );
        return list.stream().map(WeChatGroupMemberDO::getChatId).collect(Collectors.toList());
    }

    @Override
    public List<WeChatGroupDO> getChatListListByWeCustomerId(String weCustomerId) {
        List<String> list = getChatIdListByWeCustomerId(weCustomerId);
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        //
        return weChatGroupMapper.selectList(
                new LambdaQueryWrapperX<WeChatGroupDO>()
                        .in(WeChatGroupDO::getChatId, list)
        );
    }

    /**
     * <pre>
     * 获取客户群列表
     * 最后更新：2023/12/01
     * 该接口用于获取配置过客户群管理的客户群列表。
     *
     * 请求方式：POST（HTTPS）
     * 请求地址：https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/list?access_token=ACCESS_TOKEN
     * </pre>
     *
     * @return
     * @author PetePower
     * @since 2024-07-23
     */

    @Override
    public Boolean syncChatGroup() {
//
//        return true;

        checkLockStatus();
        // 发起一个异步消息通知
        syncChatGroupProducer.sendMessage(TenantContextHolder.getTenantId());
        return true;
    }

    @Override
    public void syncChatGroupByMQ() {
        WeComApiConfigDO apiConfig = weComApiConfigService.getWeComApiConfig();
        String accessToken = apiConfig.getAccessToken();
        exec(accessToken, null);
    }

    @Override
    public void updateChatGroupHandle(Map<String, Object> allFieldsMap) {
        // 客户群变更的消息，需要处理的是：
        // 1. 成员入群、退群
        // 2. 如果是退群、则删除相关人员， 否则， 就执行getChatGroup()
//        Object UpdateDetail = allFieldsMap.get("UpdateDetail");
        String ChatId = allFieldsMap.get("ChatId").toString();
        String AuthCorpId = allFieldsMap.get("AuthCorpId").toString();
        // TODO 客户群成员入群、退群事件 -->
//        if (Objects.equals("del_member", UpdateDetail)) {
//            List<String> MemChangeList = (List<String>) allFieldsMap.get("MemChangeList");
//            log.info("检测到成员退群： {}", MemChangeList);
//        }
        WeComApiConfigDO config = weComApiConfigService.getWeComApiConfigByCorpId(AuthCorpId);
        if (Objects.nonNull(config)) {
            TenantUtils.execute(config.getTenantId(), () -> {
                getChatGroup(ChatId, 0, config.getAccessToken());
            });
        }
    }

    @Override
    public void dismissChatGroupHandle(Map<String, Object> allFieldsMap) {
        String AuthCorpId = allFieldsMap.get("AuthCorpId").toString();
        String ChatId = allFieldsMap.get("ChatId").toString();
        WeComApiConfigDO config = weComApiConfigService.getWeComApiConfigByCorpId(AuthCorpId);
        if (Objects.nonNull(config)) {
            TenantUtils.execute(config.getTenantId(), () -> {
                WeChatGroupDO chatGroupDO = getWeChatGroupByChatId(ChatId);
                if (Objects.nonNull(chatGroupDO)) {
                    weChatGroupMapper.deleteById(chatGroupDO.getId());
                    // 删除群成员
                    weChatGroupMemberMapper.delete(new LambdaQueryWrapperX<WeChatGroupMemberDO>().eq(WeChatGroupMemberDO::getChatId, ChatId));
                    // 删除群会话记录？
                }
            });
        }
    }

    @Override
    public void createChatGroupHandle(Map<String, Object> allFieldsMap) {
        String AuthCorpId = allFieldsMap.get("AuthCorpId").toString();
        String ChatId = allFieldsMap.get("ChatId").toString();
        WeComApiConfigDO config = weComApiConfigService.getWeComApiConfigByCorpId(AuthCorpId);
        if (Objects.nonNull(config)) {
            TenantUtils.execute(config.getTenantId(), () -> {
                getChatGroup(ChatId, 0, config.getAccessToken());
            });
        }
    }

    public void exec(String accessToken, String cursor) {
        Map<String, Object> postData = new HashMap<>();
        postData.put("status_filter", 0);
        postData.put("limit", 100);
        if (StrUtil.isNotEmpty(cursor)) {
            postData.put("cursor", cursor);
        }
        WeApi weApi = new WeApi(accessToken).body(postData);
        JSONObject respJson = weApi.getChatGroupList();
        JSONArray jsonArray = respJson.getJSONArray("group_chat_list");
        String nextCursor = respJson.getStr("next_cursor");
        // 1. 获取到chat_id 列表
        // 2. 获取客户群详情
        // 3. 入库客户群成员，并且标识是否为管理员
        jsonArray.forEach(obj -> {
            JSONObject listItem = JSONUtil.parseObj(obj);
            log.info("chat_item:{}",listItem);
            getChatGroup(listItem.getStr("chat_id"), listItem.getInt("status"), accessToken);
        });
        if (StrUtil.isNotEmpty(nextCursor)) {
            exec(accessToken, nextCursor);
        }
        
    }

    public void getChatGroup(String chatId, Integer status, String accessToken) {
        Map<String, Object> postData = new HashMap<>();
        postData.put("chat_id", chatId);
        postData.put("need_name", 1);
        JSONObject respJson;
        try{
            WeApi weApi = new WeApi(accessToken).body(postData);
            respJson = weApi.getChatGroupInfo();
        }catch (Exception e){
            log.info("获取群详情PostData:{}",postData);
            log.info("获取群详情异常:{}", e.getMessage());
            return;
        }
        if (ObjectUtil.equal(0, respJson.getInt("errcode"))) {
            JSONObject chatInfo = respJson.getJSONObject("group_chat");
            WeChatGroupDO chatGroup = weChatGroupMapper.selectOne(WeChatGroupDO::getChatId, chatId);
            if (Objects.isNull(chatGroup)) {
                chatGroup = new WeChatGroupDO();
            }
            final String ownerUserId = chatInfo.getStr("owner");
            chatGroup.setChatId(chatId);
            chatGroup.setName(chatInfo.getStr("name"));
            chatGroup.setNotice(chatInfo.getStr("notice"));
            chatGroup.setOwner(ownerUserId);
            chatGroup.setCreateTime(LocalDateTimeUtil.of(new Date(chatInfo.getLong("create_time") * 1000)));
            chatGroup.setStatus(status);
            // 入库
            weChatGroupMapper.insertOrUpdate(chatGroup);
            Long chatGroupId = chatGroup.getId();
            // 管理员列表
            JSONArray adminList = chatInfo.getJSONArray("admin_list");
            List<String> adminUserList = adminList.stream().map(obj -> {
                return JSONUtil.parseObj(obj).getStr("userid");
            }).collect(Collectors.toList());
            // 入库member
            JSONArray memberList = chatInfo.getJSONArray("member_list");
            memberList.forEach(obj -> {
                JSONObject memberInfo = JSONUtil.parseObj(obj);
                // 查找数据
                String weUserId = memberInfo.getStr("userid");
                WeChatGroupMemberDO member = weChatGroupMemberMapper.selectOne(WeChatGroupMemberDO::getChatGroupId, chatGroupId, WeChatGroupMemberDO::getWeUserId, weUserId);
                if (Objects.isNull(member)) {
                    member = new WeChatGroupMemberDO();
                }
                member.setWeUserId(weUserId);
                member.setType(memberInfo.getInt("type"));
                member.setJoinTime(LocalDateTimeUtil.of(new Date(memberInfo.getLong("join_time") * 1000)));
                member.setJoinScene(memberInfo.getInt("join_scene"));
                if (Objects.nonNull(memberInfo.getJSONObject("invitor"))) {
                    member.setInvitor(memberInfo.getJSONObject("invitor").getStr("userid"));
                }
                member.setGroupNickname(memberInfo.getStr("group_nickname"));
                member.setName(memberInfo.getStr("name"));
                member.setUnionid(memberInfo.getStr("unionid"));
                member.setChatGroupId(chatGroupId);
                member.setChatId(chatId);
                member.setUserType(0);
                if (CollUtil.contains(adminUserList, weUserId)) {
                    member.setUserType(1);
                }
                if (StrUtil.equals(ownerUserId, weUserId)) {
                    member.setUserType(2);
                }
                weChatGroupMemberMapper.insertOrUpdate(member);
                log.info("客户群成员入库: {}", member);
            });
        }
    }

    private void checkLockStatus() {
        String lock = stringRedisTemplate.opsForValue().get(LOCK_KEY + TenantContextHolder.getTenantIdStr());
        if (StrUtil.isEmpty(lock)) {
            stringRedisTemplate.opsForValue().set(
                    LOCK_KEY + TenantContextHolder.getTenantIdStr(),
                    "LOCK",
                    30,
                    TimeUnit.MINUTES
            );
        } else {
            throw exception(SYNC_ERROR_API_LIMIT);
        }
    }
}